#ifndef _POLYNOMIAL_CPP_
#define _POLYNOMIAL_CPP_

#include "Polynomial.h"

template<int Order,class CoefType>
Polynomial<Order,CoefType>::Polynomial(vector<CoefType> arr):d(Order)
{
  Coef=arr;
}
template<int Order,class CoefType>
template<int Ord1>
Polynomial<Order,CoefType>& Polynomial<Order,CoefType>::operator=(const Polynomial<Ord1,CoefType> &p)
{
  d=Ord1;
  Coef=p.get_Coef();
  return *this;
}
  

  
template<int Ord1,int Ord2,class Type> 
Polynomial<(Ord1>=Ord2)?Ord1:Ord2,Type> operator+(const Polynomial<Ord1,Type> &p1,const Polynomial<Ord2,Type> &p2)
{
  if(Ord1>=Ord2){
    Polynomial<(Ord1>=Ord2)?Ord1:Ord2,Type> p(p1.Coef);
    for(int i=0;i<Ord2;i++)
      p.Coef[i]=p.Coef[i]+p2.Coef[i];
    return p;
  }
  else
    {
      Polynomial<(Ord1>=Ord2)?Ord1:Ord2,Type> p(p2.Coef);
      for(int i=0;i<Ord1;i++)
	p.Coef[i]=p.Coef[i]+p1.Coef[i];
      return p;
    }
}
template<int Ord1,int Ord2,class Type> 
Polynomial<(Ord1>=Ord2)?Ord1:Ord2,Type> operator-(const Polynomial<Ord1,Type> &p1,const Polynomial<Ord2,Type> &p2)
{
  return (-1.0)*p2+p1;
}


template<int Ord1,int Ord2,class Type>
Polynomial<Ord1+Ord2-1,Type> operator*(const Polynomial<Ord1,Type> &p1,const Polynomial<Ord2,Type> &p2)
{
  vector<Type> arr(Ord1+Ord2-1);
  for(int i=0;i<Ord1+Ord2-1;i++)
    arr[i]=p1.Coef[0];
  Polynomial<Ord1+Ord2-1,Type> f(arr);
  for(int i=0;i<Ord1;i++)
    for(int j=0;j<Ord2;j++)
      {
	f.Coef[i+j]=f.Coef[i+j]+p1.Coef[i]*p2.Coef[j];
      }
  for(int i=0;i<Ord1+Ord2-1;i++)
    f.Coef[i]=f.Coef[i]-p1.Coef[0];
  return f;
}

template<int Ord,class Type>
Polynomial<Ord,Type> operator*(Type c,const Polynomial<Ord,Type> &p)
{
  Polynomial<Ord,Type> P(p.Coef);
  for(int i=0;i<p.d;i++)
    P.Coef[i]=c*P.Coef[i];
  return P;
}
// template<int Ord,class Type>
// Polynomial<Ord,Type> operator*(double c,const Polynomial<Ord,Type> &p)
// {
//   Polynomial<Ord,Type> P(p.Coef);
//   for(int i=0;i<p.d;i++)
//     P.Coef[i]=P.Coef[i]*c;
//   return P;
// }
template<int Ord,class Type>
Polynomial<Ord,Type> operator+(Type c,const Polynomial<Ord,Type> &p)
{
  Polynomial<Ord,Type> P(p.Coef);
  P.Coef[0]=P.Coef[0]+c;
  return P;
}


template<int Order,class CoefType>
CoefType Polynomial<Order,CoefType>::get_value(double x)const
{
  CoefType _sum=Coef[0];
  for(int i=1;i<d;i++)
    _sum=_sum+Coef[i]*pow(x,i);
  return _sum;
}

template<int Order,class CoefType>
Polynomial<Order,CoefType> Polynomial<Order,CoefType>:: get_deri()const
{
  Polynomial<Order,CoefType> f(Coef);
  for(int i=0;i<d-1;i++)
    f.Coef[i]=Coef[i+1]*(i+1);
  f.Coef[d-1]=0;
  return f;  
}

template<int Order,class CoefType>
CoefType Polynomial<Order,CoefType>::get_deri_value(double x)const
{
  Polynomial<Order,CoefType> f=this->get_deri();
  return f.get_value(x);
}

template<int Order,class CoefType>
vector<CoefType> Polynomial<Order,CoefType>:: get_Coef()const{return Coef;}

template<int Order,class CoefType>
void Polynomial<Order,CoefType>::print()const
{
  for(int i=d-1;i>=1;i--)
    cout<<Coef[i]<<"t^"<<i<<"+";
  cout<<Coef[0]<<endl;
}




template<int Ord,class Type>
ostream& operator<<(ostream& os,const Polynomial<Ord,Type> &p)
{
  int n,k;
  for(k=p.d-1;k>=0;k--)
    if(p.Coef[k]!=0)
      break;
  n=k+1;
  for(int i=n-1;i>=1;i--)
      if(p.Coef[i]!=0)
	{
	  if(abs(p.Coef[i])!=1)
	    {
	      if(i==1){
	      if(i==n-1)
		os<<p.Coef[i]<<"x";
	      else
		{
		  if(p.Coef[i]>0)
		    os<<"+"<<p.Coef[i]<<"x";
		  else
		    os<<"-"<<abs(p.Coef[i])<<"x";
		}
	      }
	      else
		{
		  if(i==n-1)
		    os<<p.Coef[i]<<"x^"<<i;
		  else
		    {
		      if(p.Coef[i]>0)
			os<<"+"<<p.Coef[i]<<"x^"<<i;
		      else
			os<<"-"<<abs(p.Coef[i])<<"x^"<<i;
		    }
		}
	    }
	  else
	    {
	      if(i==1){
	      if(i==n-1)
		if(p.Coef[i]==1)
		  os<<"x";
		else
		  os<<"-"<<"x";
	      else
		if(p.Coef[i]==1)
		  os<<"+"<<"x";
		else
		  os<<"-"<<"x";
	      }
	      else
		{
		  if(i==n-1)
		    if(p.Coef[i]==1)
		      os<<"x^"<<i;
		    else
		      os<<"-"<<"x^"<<i;
		  else
		    if(p.Coef[i]==1)
		      os<<"+"<<"x^"<<i;
		    else
		      os<<"-"<<"x^"<<i;
		}
	    }
	}
  if(p.d!=0)
    if(p.Coef[0]!=0)
      {
	if(p.Coef[0]>0) os<<"+"<<p.Coef[0];
	else os<<"-"<<abs(p.Coef[0]);
      }
  if(p.d==0)
    os<<p.Coef[0];
  return os;
}

#endif
